﻿using MSScriptControl;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace RulesHandlerProcess
{
    class xmlRuleEngine
    {
         #region 构造函数和属性部分
        public Dictionary<string, string> listvalue = new Dictionary<string, string>();
        public ArrayList arr = new ArrayList();
        private string wherepara;     //记录where中判断的参数

        public string Wherepara
        {
            get { return wherepara; }
            set { wherepara = value; }
        }

        private bool wheretrues;       //设置个变量判断where的判断结果，

        public bool Wheretrues
        {
            get { return wheretrues; }
            set { wheretrues = value; }
        }
        private string casestype;

        public string Casestype
        {
            get { return casestype; }
            set { casestype = value; }
        }

        private int calnum;

        public int Calnum
        {
            get { return calnum; }
            set { calnum = value; }
        }

        private string caltype;

        public string Caltype
        {
            get { return caltype; }
            set { caltype = value; }
        }

        private Dictionary<string, string> dicpara = new Dictionary<string, string>();

        public Dictionary<string, string> Dicpara        //传入参数的集合
        {
            get { return dicpara; }
            set { dicpara = value; }
        }
        private double price;

        public double Price                  //需要计算输出的价格
        {
            get { return price; }
            set { price = value; }
        }

        public xmlRuleEngine (Dictionary<string, string> dr)  //带参数的构造函数
        {
            dicpara = dr;
        }

        public xmlRuleEngine()      //无参数的构造函数
        {

        }

        #endregion

        #region 主函数部分

        #region 递归部分，函数逻辑核心

        //xml文档主题循环，分割为以where的程序块
        public void Recursion(XmlNode xn)
        {
            if (xn.Name == "unit")
            {
                if (xn.Attributes["mainrule"].Value.Equals("null") ==false)
                {
                    mainrule(xn, dicpara);
                    listvalue.Clear();
                    this.wheretrues = true;
                }
            }
            if (xn.Name == Convert.ToString(keywords.where))
            {
                Where(xn);
                if (xn.NextSibling != null)
                {
                    xn = xn.NextSibling;
                }
                if (this.wheretrues == true)
                {
                    this.price = SetPrice();
                    listvalue.Clear();
                }
                else
                {
                    this.wheretrues = true;
                }

                //arr.AddRange(arraywhere);
                //arraywhere.Clear();
            }
           
            //if (xn.Name == "where")
            //{
            //    Where(xn);
            //    listvalue.Clear();
            //    this.wheretrues = true;
            //}
            if (xn.HasChildNodes)
            {
                XmlNodeList children = xn.ChildNodes;
                foreach (XmlNode child in children)
                {
                    Recursion(child);
                }
            }

        }
        public void mainrule(XmlNode xn,Dictionary<string,string> dic)
        {
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(AppDomain.CurrentDomain.BaseDirectory + @"Rules\" + xn.Attributes["mainrule"].Value.Trim() + ".xml");
            XmlNode xmlmainnode = xmldoc.SelectSingleNode("//rule");
            xmlRuleEngine xmlreader = new xmlRuleEngine(dic);
            xmlreader.Recursion(xmlmainnode);
            this.price = xmlreader.GetPrice();
        }

       
        
        public void Where(XmlNode xn)
        {
            if (xn.Name == Convert.ToString(keywords.ext))
            {
                this.price = SetPrice();
                this.listvalue.Clear();
                Recursion(xn);
                return;//判断是否有ext子字节，若有则退出继续调用Recursion方法，递归此附加方法
            }
            else
            {
                if (xn.Name == Convert.ToString(keywords.where))
                {
                    if (wherefunction(xn) == false)  //  判断where节点的if执行结果是否为真，若不为真，直接跳出整个where程序块
                    {
                        this.wheretrues = false;
                        return;
                    }
                }
                switch (xn.Name)
                {
                    case "cal": calfunction(xn); break;
                    case "cases": casefunction(xn); break;
                    case "list": listfunction(xn); break;
                    case "addition": additionfunction(xn); break;
                }

            

                if (xn.HasChildNodes)//子节点
                {
                    XmlNodeList children = xn.ChildNodes;
                    foreach (XmlNode child in children)
                    {
                        Where(child);
                    }
                }
            }
        }

        #endregion


        #region 字节处理函数以及计算函数，函数部分主体

        public bool wherefunction(XmlNode xn)
        {
            Dictionary<string, string> wheredic = new Dictionary<string, string>();
            if (xn.Attributes != null)
            {
                foreach (XmlAttribute attr in xn.Attributes)
                {
                    wheredic.Add(attr.Name, attr.Value);
                }
                if (wheredic.ContainsValue("default") == true)
                {
                    return true;
                }
                else
                {
                    if (wheredic.ContainsKey("name") == true)
                    {
                        this.wherepara =dicpara[ wheredic["name"]];

                        if (wheredic.ContainsKey("judgement") == true)
                        {
                            Dictionary<string, string> judgement = BracketHandler(wheredic["judgement"]);
                            #region Contains top keywords
                            if (judgement["rightnum"] == "top")
                            {
                                if(judgement["leftsign"]=="more")
                                {
                                    if (ToDouble(dicpara[wheredic["name"]]) > ToDouble(judgement["leftnum"]))
                                    {
                                        this.wheretrues = true;
                                        return true;
                                    }
                                    else
                                    {
                                        return false;
                                    }
                                }
                                else if (judgement["leftsign"] == "emore")
                                {
                                    if (ToDouble(dicpara[wheredic["name"]]) >= ToDouble(judgement["leftnum"]))
                                    {
                                        this.wheretrues = true;
                                        return true;
                                    }
                                    else
                                    {
                                        return false;
                                    }
                                }
                            }
                            #endregion
                            #region no top keywords include
                            else
                            {
                                if (judgement["leftsign"] == "more" && judgement["rightsign"] == "less")
                                {
                                    if (ToDouble(dicpara[wheredic["name"]]) > ToDouble(judgement["leftnum"]) && ToDouble(dicpara[wheredic["name"]]) < ToDouble(judgement["rightnum"]))
                                    {
                                        this.wheretrues = true;
                                        return true;
                                    }
                                    else
                                    {
                                        return false;

                                    }
                                }
                                else if (judgement["leftsign"] == "emore" && judgement["rightsign"] == "less")
                                {
                                    if (ToDouble(dicpara[wheredic["name"]]) >= ToDouble(judgement["leftnum"]) && ToDouble(dicpara[wheredic["name"]]) < ToDouble(judgement["rightnum"]))
                                    {
                                        this.wheretrues = true;
                                        return true;
                                    }
                                    else
                                    {
                                        return false;

                                    }
                                }
                                else if (judgement["leftsign"] == "more" && judgement["rightsign"] == "eless")
                                {
                                    if (ToDouble(dicpara[wheredic["name"]]) > ToDouble(judgement["leftnum"]) && ToDouble(dicpara[wheredic["name"]]) <= ToDouble(judgement["rightnum"]))
                                    {
                                        this.wheretrues = true;
                                        return true;
                                    }
                                    else
                                    {
                                        return false;

                                    }
                                }
                                else
                                    if (judgement["leftsign"] == "emore" && judgement["rightsign"] == "eless")
                                    {
                                        if (ToDouble(dicpara[wheredic["name"]]) >= ToDouble(judgement["leftnum"]) && ToDouble(dicpara[wheredic["name"]]) <= ToDouble(judgement["rightnum"]))
                                        {
                                            this.wheretrues = true;
                                            return true;
                                        }
                                        else
                                        {
                                            return false;

                                        }
                                    }
                                    else
                                    {

                                        return false;
                                    }
                            }
                            #endregion
                        }
                    }
                    return false;
                }
            
            }
            else
            {
                this.wheretrues = true;
                return true;
            }
        }

        public void additionfunction(XmlNode xn)
        { 
        
        }

        public void calfunction(XmlNode xn)
        {
            Dictionary<string, string> caldic = AttributeStore(xn);

            this.caltype = caldic["caltype"];

            ScriptControl smc = new ScriptControlClass();
            smc.UseSafeSubset = true;
            smc.Language = "VBScript";
           
            if (caldic.ContainsKey("cal") == false)
            {
                caldic["cal"] = "1";
                this.calnum = Convert.ToInt32(smc.Eval(caldic["cal"]));
            }
            else
            {
                caldic["cal"] = Replacevar(caldic["cal"], this.wherepara);
                this.calnum = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(smc.Eval(caldic["cal"]))));
            }
        }

        public void casefunction(XmlNode xn)
        {
            Dictionary<string, string> cases = AttributeStore(xn);
            this.casestype = cases["name"];
        }

        public void listfunction(XmlNode xn)
        {
            if (xn.Attributes != null)
            {
                listvalue.Add(xn.Attributes[0].Value, xn.FirstChild.Value);
            }
        }

        public double SetPrice()
        {
            if (this.caltype == "add")
            {
                
                
                    if (this.casestype == "default")
                    {
                        price += Convert.ToDouble(listvalue["default"]);
                    }
                    else
                    {
                        if (listvalue.ContainsKey(dicpara[this.casestype]))
                        price += this.calnum * ToDouble(listvalue[dicpara[this.casestype]]);
                        return price;
                    }
                    return price;
                
               
            }
            else if (this.caltype == "prop")
            {
                price = price * this.calnum * ToDouble(listvalue[dicpara[this.casestype]]);
                return price;
            }
            else
            {
                this.price = 0;
                return price;
            }
        }

        #endregion


        #endregion

        #region 返回函数，输出price

        public double GetPrice()         //返回最终计算的结果值，price。
        {
            return this.price;
        }

        #endregion

        #region 附加函数部分

        public string Replacevar(string cal, string rep)
        {
            string res= cal.Replace("var", rep);
            return res;
        }
        

        public string omission(string value)
        {
            string str = value.Trim();
            if (str.Contains(",") == true)
            {
                return str;
            }
            else
            {
                if (str.Contains(")"))
                {
                    string[] arr = str.Split(')');
                    str = arr[0] + ",top)" + arr[1];
                    return str;
                }
                else if (str.Contains("]"))
                {
                    string[] arr = str.Split(']');
                    str = arr[0] + ",top]" + arr[1];
                    return str;
                }
                else
                {
                    return null;
                }
            }
        }


        public Dictionary<string, string> BracketHandler(string value)
        {
            Dictionary<string, string> dicbracket = new Dictionary<string, string>();
            string str = value.Trim();
            str = omission(str);
            string[] lstr = str.Split(',');
            char[] sublstr = lstr[0].ToCharArray();
            char[] subrstr = lstr[1].ToCharArray();
            if (sublstr[0] == '(')
            {
                dicbracket.Add("leftsign", "more");
                try
                {
                    dicbracket.Add("leftnum", lstr[0].Split('(')[1].Trim());
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else if (sublstr[0] == '[')
            {
                dicbracket.Add("leftsign", "emore");
                try
                {
                    dicbracket.Add("leftnum", lstr[0].Split('[')[1].Trim());
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else
            {
                dicbracket.Add("leftsign", "error");
                dicbracket.Add("leftnum", "error");
            }
            if (subrstr[subrstr.Length - 1] == ')')
            {
                dicbracket.Add("rightsign", "less");
                try
                {
                    dicbracket.Add("rightnum", lstr[1].Split(')')[0].Trim());
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else if (subrstr[subrstr.Length - 1] == ']')
            {
                dicbracket.Add("rightsign", "eless");
                try
                {
                    dicbracket.Add("rightnum", lstr[1].Split(']')[0].Trim());
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            else
            {
                dicbracket.Add("rightsign", "error");
                dicbracket.Add("rightnum", "error");
            }
            return dicbracket;
        }

        public Dictionary<string, string> AttributeStore(XmlNode xn)    //将attributes集合中的属性值放在attributestore键值对中。
        {
            Dictionary<string, string> store = new Dictionary<string, string>();
            if (xn.Attributes != null)
            {
                foreach (XmlAttribute attr in xn.Attributes)
                {
                    store.Add(attr.Name, attr.Value);
                }
                return store;
            }
            else
            {
                return null;
            }
        }
      
        public double ToDouble(string item)       //将string类型的值强制转换为double类型，方便计算，并且添加了异常处理，当发生异常，值设为一，以后可以在日志记录中添加错误日志。
        {
            try
            {
                return Convert.ToDouble(item);
            }
            catch
            {

                return 0;
            }
        }

        public string GetParaValue(string key)      //根据参数的键值取出其value值。
        {
            foreach (KeyValuePair<string, string> item in this.dicpara)
            {
                if (item.Key == key)
                {
                    return item.Value;
                }
            }
            return null;
        }

        public enum keywords             //字节名的枚举集合
        {
            where,
            ext,
            cal,
            cases,
            list,
        }
        #endregion
    }
}
